/**
 * File Name: Vis.java
 *
 * Date: 18/12/2009
 *
 * Copyright (c) 2006 Michael LaLena. All rights reserved.  (www.lalena.com)
 * Permission to use, copy, modify, and distribute this Program and its documentation,
 *  if any, for any purpose and without fee is hereby granted, provided that:
 *   (i) you not charge any fee for the Program, and the Program not be incorporated
 *       by you in any software or code for which compensation is expected or received;
 *   (ii) the copyright notice listed above appears in all copies;
 *   (iii) both the copyright notice and this Agreement appear in all supporting documentation; and
 *   (iv) the name of Michael LaLena or lalena.com not be used in advertising or publicity
 *          pertaining to distribution of the Program without specific, written prior permission.
 */
package model;

import gui.Constanten;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

/**
 * Afgeleide klasse van Dier
 * Bevat de eigenschappen en methodes van hoe een vis zich gedraagt tov zijn omgeving
 *
 * @author Michiel Declercq
 * @author Stijn Delbeke
 * @author Dieter Deriemaeker
 * @author Gregory Nickmans
 *
 * @author Michael LaLena
 *
 */
public class Vis extends Dier {

    /**
     * Constructor
     *
     * @param  x x-coördinaat
     * @param  y y-coördinaat
     */
    public Vis(int x, int y) {
        super(x, y, Constanten.GROOTTE_VIS, (int) (Math.random() * 360), Constanten.KLEUR_VIS);
        this.setCurrentSpeed(Constanten.MAX_SNELHEID_VIS);
        this.setMaxTurnTheta(Constanten.MAX_THETA_VIS);

        Aquarium.aantalVissen++;
    }

    /**
     * Het gedrag van een vis
     * Is het dichtst bijzijnde object een obstakel of een orka, vlucht
     * Is dit een vis, vorm een school
     *
     * @param aq Het aquarium (omgeving)
     * @param anderObject een object binnen de omgeving
     * @param target Som van de posities van alle objecten binnen het zicht
     * @return Point
     */
    public Point Handling(Aquarium aq, AquariumObject anderObject, Point target) {
        Point otherLocation = closestLocation(this.location, anderObject.location);
        int distance = this.getDistance(otherLocation);

        if (!(this.equals(anderObject)) && (distance > 0) && distance <= DetectionRange) {
            //Ander object is ook een vis en is binnen het bereik
            //->Aligneren
            if ((anderObject instanceof Vis)) {
                //System.out.println("align");
                Vis andereVis = (Vis) anderObject;
                aq.verhoogNumDieren();
                Point align = new Point((int) (100 * Math.cos(andereVis.getCurrentTheta() * Math.PI / 180)),
                        (int) (-100 * Math.sin(andereVis.getCurrentTheta() * Math.PI / 180)));
                align = normalisePoint(align, 100); // alignment weight is 100

                boolean tooClose = (distance < SeparationRange);
                double weight = 200.0;
                if (tooClose) {
                    weight *= Math.pow(1 - (double) distance / SeparationRange, 2);
                }
                else {
                    weight *= -Math.pow((double) (distance - SeparationRange) / (DetectionRange - SeparationRange), 2);
                }

                Point attract = sumPoints(otherLocation, -1.0, this.location, 1.0);
                attract = normalisePoint(attract, weight);
                Point dist = sumPoints(align, 1.0, attract, 1.0);
                dist = normalisePoint(dist, 100); // max weight 100

                target = sumPoints(target, 1.0, dist, 1.0);

            }
            //Ander object is een Orka
            //->Vluchten
            else if (anderObject instanceof Orka) {
                Point dist = sumPoints(this.location, 1.0, otherLocation, -1.0);
                dist = normalisePoint(dist, 1000);
                double weight = Math.pow((1 - (double) distance / DetectionRange), 2);
                target = sumPoints(target, 1.0, dist, weight); // weight is variable
            }
        }
        //Ander object is een Obstakel
        //->Vermijden
        else if (anderObject instanceof Obstakel) {
            double r = Constanten.DETECTION_DISTANCE;
            Ellipse2D ell = new Ellipse2D.Double(this.location.x - r, this.location.y - r, 2 * r, 2 * r);
            Rectangle2D rect = ell.getBounds2D();
            Obstakel obst = (Obstakel) anderObject;
            if (rect.intersects(obst.location.x, obst.location.y, obst.size.width, obst.size.height)) {
                Point dist = sumPoints(this.location, 1.0, obst.getCenter(), -1.0);
                dist = normalisePoint(dist, 1000);
                double weight = 10 * Math.pow((1 - (double) distance / DetectionRange), 2);
                target = sumPoints(target, 1.0, dist, weight);
            }
        }
        return target;
    }
}
